﻿using Flurl.Http;
using Flurl.Http.Configuration;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using MudBlazor.Services;
using MudExtensions.Services;
using MXERP.Blazor.Extensions;
using MXERP.Client.Components;
using MXERP.Infrastructure.Authentication;
using MXERP.Infrastructure.Managers;
using MXERP.Shared.Constants;
using MXERP.Shared.Consts;
using MXERP.Shared.JsonConverters;
using MXERP.Shared.Security;
using System.Reflection;
using System.Text.Json;
using TimeWarp.Features.RenderSubscriptions;

namespace MXERP.Client.Extensions;

public static class ClientServiceCollectionExtension
{
    private const string ClientName = "MXERP.Api";

    public static IServiceCollection AddClientServices(this IServiceCollection services, IConfiguration config)
    {
        //services.AddFluxor(options => options.ScanAssemblies(typeof(RouteState).Assembly).UseReduxDevTools());
        services.AddTimeWarpState(options =>
        {
            options.UseReduxDevTools();
            options.Assemblies = 
            [
                typeof(RouteState).GetTypeInfo().Assembly,
            ];
        });
        services.AddScoped<RenderSubscriptionContext>();
        services.AddLocalization(options => options.ResourcesPath = "Resources");
        services.AddBlazoredLocalStorage();
        services.AddMudServices(configuration =>
        {
            configuration.SnackbarConfiguration.PreventDuplicates = false;
            configuration.SnackbarConfiguration.MaxDisplayedSnackbars = 50;
            configuration.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.TopCenter;
            configuration.SnackbarConfiguration.HideTransitionDuration = 500;
            configuration.SnackbarConfiguration.ShowTransitionDuration = 500;
            configuration.SnackbarConfiguration.VisibleStateDuration = 3000;
            configuration.SnackbarConfiguration.ShowCloseIcon = false;
            //configuration.SnackbarConfiguration.SnackbarVariant = Variant.Text;
        });
        services.AddMXERPBlazorServices();
        services.AddMudExtensions();
        services.AddScoped<IUserPreferenceService, UserPreferenceService>();
        services.AddScoped<CustomStateProvider>();
        services.AddScoped<AuthenticationStateProvider, CustomStateProvider>();
        services.AutoRegisterInterfaces<IManager>();
        services.AddSingleton<CustomDelegatingHandler>();
        services.AddScoped<LayoutService>();
        services.AddAuthorizationCore(RegisterLicenseClaims);
        services.AddSingleton(sp => new FlurlClientCache()
            // all clients:
            .WithDefaults(builder =>
            {
                builder.Headers.Add("Accept", "application/json");
                builder.WithSettings(option =>
                {
                    option.JsonSerializer = new DefaultJsonSerializer(new JsonSerializerOptions()
                    {
                        PropertyNameCaseInsensitive = true,
                        IgnoreReadOnlyProperties = true,
                        Converters = { new DateTimeJsonConverter() }
                    });
                });
            })
            // specific named client:
            .Add(ApiConstant.MXERP, "http://localhost:9001", builder =>
            {
                builder.AddMiddleware(sp.GetRequiredService<CustomDelegatingHandler>);
            })
        );
        services.RegisterMapster(options =>
        {
            options.Default.PreserveReference(true);
            options.AllowImplicitDestinationInheritance = true;
        });
        //services.AddScoped<ReuseTabsService>();

        return services;
    }

    // Add Api Http Client.
    //.AddHttpClient(ClientName, client =>
    //    {
    //        client.DefaultRequestHeaders.AcceptLanguage.Clear();
    //        client.DefaultRequestHeaders.AcceptLanguage.ParseAdd(CultureInfo.DefaultThreadCurrentCulture?.TwoLetterISOLanguageName);
    //        client.BaseAddress = new Uri(config["ApiBaseUrl"] ?? "");
    //    })
    //    .AddHttpMessageHandler<AuthenticationHeaderHandler>()
    //    .Services
    //.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient(ClientName));
    private static void RegisterLicenseClaims(AuthorizationOptions options)
    {
        foreach (var prop in typeof(LicenseConst).GetNestedTypes().SelectMany(c => c.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)))
        {
            var propertyValue = prop.GetValue(null);
            if (propertyValue is not null)
            {
                options.AddPolicy(propertyValue.ToString()!, policy => policy.RequireClaim(MXERPClaimTypes.License, propertyValue.ToString()!));
            }
        }
    }

    public static IServiceCollection AutoRegisterInterfaces<T>(this IServiceCollection services)
    {
        var @interface = typeof(T);

        var types = @interface
            .Assembly
            .GetExportedTypes()
            .Where(t => t.IsClass && !t.IsAbstract)
            .Select(t => new
            {
                Service = t.GetInterface($"I{t.Name}"),
                Implementation = t
            })
            .Where(t => t.Service != null);

        foreach (var type in types)
        {
            if (@interface.IsAssignableFrom(type.Service))
            {
                services.AddScoped(type.Service, type.Implementation);
            }
        }

        return services;
    }
}